package com.weixing.mall.pay.channel.ali;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.weixing.mall.pay.IPayment;
import com.weixing.mall.pay.PayParam;
import com.weixing.mall.pay.PayResult;
import com.weixing.mall.pay.QueryResult;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName AbstractAliPay
 * @Description
 * @Author Small
 * @Date 2019/11/29 19:52
 * @Version 1.0
 **/
@Slf4j
public abstract class AbstractAliPay implements IPayment {

    protected AlipayClient alipayClient;
    private AlipayTradeQueryRequest alipayQueryRequest;
    protected  AliPaySet aliPaySet;

    public AbstractAliPay(AliPaySet aliPaySet) {
        this.aliPaySet = aliPaySet;
    }

    /**
     * 方法描述: 统一下单接口
     * @Author Small
     * @param payParam
     * @Date 2019/11/29 17:41
     * @return com.weixing.mall.pay.PayResult
     */
    @Override
    public final PayResult pay(PayParam payParam) {
        String outTransNo = payParam.getOutTransNo();
        String tradeType = getTradeType().getValue();
        log.info("AliPay::{}=>订单{} 支付请求到达", tradeType, outTransNo);
        // 初始化客户端
        initClient();
        //初始化支付请求
        initAliPayRequest();
        // 设置请求参数
        setPayRequestParam(payParam);
        // 下单请求
        PayResult payResult = null;
        try {
            payResult = executePay();
            if (payResult.isSuccess()) {
                log.info("AliPay::{}=>订单{} 下单成功", tradeType, outTransNo);
            } else {
                log.info("AliPay::{}=>订单{} 下单失败,错误代码{},错误原因{}", tradeType, outTransNo, payResult.getErrCode(), payResult.getMsg());
            }
        } catch (AlipayApiException e) {
            log.warn("AliPay::{}=>订单{} 下单时发生异常", tradeType, outTransNo, e);
            payResult = PayResult.unknowException();
        }
        return payResult;
    }


    /**
     * 方法描述: 支付查询
     * @Author Small
     * @param outTradeNo
     * @Date 2019/12/2 17:03
     * @return com.weixing.mall.pay.QueryResult
     */
    @Override
    public final QueryResult query(String outTradeNo) {
        log.info("AliQuery=>订单{} 请求到达", outTradeNo);
        // 初始化客户端
        initClient();
        //初始化查询请求
        initAliPayQueryRequest();
        //设置请求参数
        setQueryRequestParam(outTradeNo);
        //查询请求
        QueryResult queryResult = null;
        try {
            queryResult = executeQuery();
            log.info("AliQuery=>订单{} 查询结果", outTradeNo, JSON.toJSONString(queryResult));
        } catch (AlipayApiException e) {
            log.warn("AliQuery=>订单{} 查询时发生异常", outTradeNo, e);
        }
        return queryResult;
    }


    /**
     * 方法描述: 初始化客户端
     * @Author Small
     * @param
     * @Date 2019/12/2 15:53
     * @return com.alipay.api.AlipayClient
     */
    protected void initClient() {
        this.alipayClient = new DefaultAlipayClient(aliPaySet.getGatewayUrl(),
                aliPaySet.getAppid(),
                aliPaySet.getMerchantPrivateKey(),
                aliPaySet.getFormat(),
                aliPaySet.getCharset(),
                aliPaySet.getAlipayPublicKey(),
                aliPaySet.getSignType());
    }


    /**
     * 方法描述: 封装支付请求参数
     * @Author Small
     * @param payParam
     * @param productCode
     * @Date 2019/12/3 15:16
     * @return java.util.Map<java.lang.String                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               java.lang.String>
     */
    protected Map<String, String> wrapperRequestData(PayParam payParam, String productCode) {
        Map<String, String> data = new HashMap<>(4);
        //商户订单号，商户网站订单系统中唯一订单号，必填
        data.put("out_trade_no", payParam.getOutTransNo());
        //付款金额，必填
        data.put("total_amount", String.valueOf(payParam.getAmount().doubleValue()));
        //订单名称，必填
        data.put("subject", payParam.getBody());
        //商品描述，可空
        data.put("body", "");
        // 销售产品码）
        data.put("product_code", productCode);
        return data;
    }


    /**
     * 方法描述: 初始化支付请求
     * @Author Small
     * @param
     * @Date 2019/12/2 16:27
     * @return com.alipay.api.AlipayRequest
     */
    public abstract void initAliPayRequest();


    /**
     * 方法描述: 初始化支付查询请求
     * @Author Small
     * @param
     * @Date 2019/12/2 16:27
     * @return com.alipay.api.AlipayRequest
     */
    private void initAliPayQueryRequest() {
        this.alipayQueryRequest = new AlipayTradeQueryRequest();
    }

    /**
     * 方法描述: 设置支付请求参数
     * @Author Small
     * @param payParam
     * @Date 2019/12/2 16:27
     * @return com.alipay.api.AlipayRequest
     */
    public abstract void setPayRequestParam(PayParam payParam);

    /**
     * 方法描述: 设置支付查询请求参数
     * @Author Small
     * @param outTradeNo
     * @Date 2019/12/2 16:27
     * @return com.alipay.api.AlipayRequest
     */
    private void setQueryRequestParam(String outTradeNo) {
        alipayQueryRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\"}");
    }

    /**
     * 方法描述: 执行查询请求
     * @Author Small
     * @param
     * @Date 2019/12/3 14:36
     * @return com.weixing.mall.pay.QueryResult
     */
    private QueryResult executeQuery() throws AlipayApiException {
        AlipayTradeQueryResponse queryResponse = alipayClient.execute(this.alipayQueryRequest);
        if (queryResponse.isSuccess()) {
            // 接口调用成功
            String tradeStatus = queryResponse.getTradeStatus();
            if (TradeStateEnum.TRADE_SUCCESS.getStatus().equals(tradeStatus)) {
                return QueryResult.tradeSuccess();
            } else {
                return QueryResult.tradeNotSuccess(tradeStatus,null);
            }
        } else {
            // 接口调用失败
            String subCode = queryResponse.getSubCode();
            String subMsg = queryResponse.getSubMsg();
            return QueryResult.fail(subCode, subMsg);
        }
    }

    /**
     * 方法描述: 执行支付请求
     * @Author Small
     * @param
     * @Date 2019/12/3 14:36
     * @return com.weixing.mall.pay.PayResult
     */
    public abstract PayResult executePay() throws AlipayApiException;

    /**
     * 方法描述: 获取交易类型
     * @Author Small
     * @param
     * @Date 2019/12/3 14:37
     * @return com.weixing.mall.pay.channel.ali.WxTradeTypeEnum
     */
    public abstract AliTradeTypeEnum getTradeType();
}
